#include "pile.h"

/*Constructeur*/
struct pile* constrPile()
{
	/*Partie pile*/
	struct pile *p=(struct pile *)malloc(sizeof(struct pile));
	p->capaciteMax=INIT_CAPACITE;
	p->base=malloc(INIT_CAPACITE*sizeof(struct element *));
	p->deplacement=0;
	p->flag=0;
	p->sommetPile=0;
	p->origine=p->base;

	/*Partie contexte*/
	p->area=malloc(INIT_CAPACITE_CONTEXTE*sizeof(struct contexte *));
	p->nContexte=0;
	p->capaciteMaxContexte=INIT_CAPACITE_CONTEXTE;
	p->flagPassageReference=0;
	p->saveBase=malloc(sizeof(struct contexte));
	return p;
}

/*Empile le pointeur de la base et positionne le nouveau pointeur de la base*/
void setBase(struct pile *p, int deplacement)
{
	if(p->nContexte < p->capaciteMaxContexte)
	{
		struct contexte *c=malloc(sizeof(struct contexte));		// Nouveau contexte
		c->deplacement=p->deplacement;
		c->base=p->base;

		p->area[p->nContexte]=c;					// Empile le contexte
		p->nContexte++;
		p->base=&p->base[p->deplacement-deplacement];			// Affectation de la nouvelle base
		p->deplacement=p->deplacement-(p->deplacement-deplacement); 
	}
	else
	{
		int nouvelleTaille=p->capaciteMaxContexte*COEF_ALLOC_CONTEXTE;
		struct contexte **nouvArea=malloc(nouvelleTaille*sizeof(struct contexte *));
		
		memcpy(nouvArea, p->area, (p->nContexte)*sizeof(struct contexte *));
		free(p->area);

		p->capaciteMaxContexte=nouvelleTaille;
		p->area=nouvArea;

		struct contexte *c=malloc(sizeof(struct contexte));     // Nouveau contexte
                c->deplacement=p->deplacement;
                c->base=p->base;

		p->area[p->nContexte]=c;
		p->nContexte++;
		p->base=&p->base[p->deplacement-deplacement];			// Affectation de la nouvelle base
		p->deplacement=p->deplacement-(p->deplacement-deplacement);
	}
}

/*Dépile un pointeur de la base et le restore*/
void releaseBase(struct pile *p, int deplacement)
{
	if(p!=NULL)
	{
		p->nContexte--;
	
		p->saveBase->base=p->base;
		p->saveBase->deplacement=p->deplacement;

		p->base=p->area[p->nContexte]->base;
		p->deplacement=p->area[p->nContexte]->deplacement;
	}
}

/*L'élément est déjà déclaré dans la table des symbôles*/
struct element* constrElement(char Nom[128], char Valeur[128], int TypeI, int TypeL, char emplacement[128])
{	
	struct element *e=malloc(sizeof(struct element));
	strcpy(e->nom, Nom);
	strcpy(e->valeur, Valeur);
	strcpy(e->localisation, emplacement);
	e->typeIdentificateur=TypeI;
	e->typeLiteral=TypeL;
	return e;
}

/*Destructeur*/
void nettoyerPile(struct pile *p)
{
	if(p->deplacement>0)
	{
		int i;

		for(i=0; i<p->deplacement; ++i)
		{
			p->deplacement--;
			free(p->base[p->deplacement]);
		}
	
		free(p->base);
		free(p->area);

		// Initialise la pile de base
		p->capaciteMax=INIT_CAPACITE;
		p->base=NULL;
		p->deplacement=0;
		p->base=malloc(INIT_CAPACITE*sizeof(struct element));
		p->sommetPile=0;
		p->origine=p->base;

		// Initialise la pile pour les contextes
		p->area=malloc(INIT_CAPACITE_CONTEXTE*sizeof(struct element **));
		p->nContexte=0;
		p->capaciteMaxContexte=INIT_CAPACITE_CONTEXTE;
	}
}

/*Empiler et dépiler*/
void empiler(struct pile *p, char Nom[128], char Valeur[128], int TypeI, int TypeL, char Localisation[128])
{
	if(p->deplacement<p->capaciteMax)
	{
		p->base[p->deplacement]=constrElement(Nom, Valeur, TypeI, TypeL, Localisation);
		p->deplacement++;
	}
	else
	{	
		int nouvelleTaille=p->capaciteMax*COEF_ALLOC;
		struct element **nouvelleBase=malloc(nouvelleTaille*sizeof(struct element *));
		
		memcpy(nouvelleBase, p->base, (p->deplacement)*sizeof(struct element *));
		free(p->base);

		p->capaciteMax=nouvelleTaille;
		p->base=nouvelleBase;

		p->base[p->deplacement]=constrElement(Nom, Valeur, TypeI, TypeL, Localisation);
		p->deplacement++;
	}

	
	p->sommetPile++;
}

struct element* depiler(struct pile *p)
{
	if(p->deplacement>0)
	{
		p->deplacement--; 
		p->sommetPile--;
		return p->origine[p->sommetPile];
	}
	else return NULL;
}


void affichagePile(struct pile *p)
{
	printf("\nInformation sur la pile:\nTaille=%d\nCapacite max=%d; Pointeur de pile=%d; \n\n", p->sommetPile, p->capaciteMax, p->deplacement);

	if(p->deplacement>0)
	{
		int i;

		for(i=0; i<p->deplacement; ++i)
		{
			char buffer[128];

			sprintf(buffer, "Nom=%s; TypeId=%d; TypeVal=%d; Valeur=%s; Localisation=%s;\n", p->base[i]->nom, p->base[i]->typeIdentificateur, p->base[i]->typeLiteral, p->base[i]->valeur, p->base[i]->localisation); 
			printf("%s", buffer);
		}
	}
}

void affichagePile2(struct pile *p)
{
	printf("\nInformation sur la pile:\nTaille=%d\nCapacite max=%d; Pointeur de pile=%d; \n\n", p->sommetPile, p->capaciteMax, p->deplacement);

	if(p->deplacement>0)
	{
		int i;

		for(i=0; i<p->sommetPile; ++i)
		{
			char buffer[128];

			sprintf(buffer, "Nom=%s; TypeId=%d; TypeVal=%d; Valeur=%s; Localisation=%s;\n", p->origine[i]->nom, p->origine[i]->typeIdentificateur, p->origine[i]->typeLiteral, p->origine[i]->valeur, p->origine[i]->localisation); 
			printf("%s", buffer);
		}
	}
}


int estPresent(struct pile *p, char nom[128], char emplacement[128])
{
	if(p!=NULL)
	{
		int i;
		for(i=0; i<p->sommetPile; ++i)
		{
			if(strcmp(p->base[i]->nom, nom)==0 && strcmp(emplacement, p->base[i]->localisation)==0) return 1;
		}
	}

	return 0;
}
void affichageContexte(struct pile *p)
{
	printf("Affichage des contextes sauvegardés\n");

	int i;
	for(i=0; i<p->nContexte; ++i)
	{
		printf("Contexte n°%d=%s sommet de pile=%d\n", i, p->area[i]->base[0]->nom, p->area[i]->deplacement);
	}

}
